<?php
class Page2Menu extends FWidget
{
    public $rootId = null;
    public $exclude = '';
    public $level = null;
    public $pages = '';
    public $minItemsToShow=2;
    //data cache
    public $expire = 900;//15'
    
    private $_data;
    
    private static $_path;
    
    public function init()
    {
        parent::init();
        Yii::trace(__CLASS__.'.'.__FUNCTION__, 'Page2Menu');
        
        $workflowId = 0;
        $siteId = 0;
        $result = FSM::_run('Cms.Workflow.lookup');
        if (!$result->hasErrors())
        {
            $workflowId = $result->model->id;
            $siteId = $result->model->site_id;
        }
        
        $pageId = property_exists(Yii::app()->controller, 'pageId') ? Yii::app()->controller->pageId : 0;
        if(($cache=Yii::app()->cache)!==null)
        {
            $key=__CLASS__.'::'.__FUNCTION__
                .Yii::app()->request->getHostInfo()
                .'#rootId'.(int) $this->rootId
                .'#exclude'.$this->exclude
                .'#level'.(int) $this->level
                .'#pages'.md5($this->pages)
                .'#minItemsToShow'.$this->minItemsToShow
                .'#pageId'.$pageId;
            if(($data=$cache->get($key))!==false)
            {
                $this->_data = unserialize($data);
                return;
            }
        }
        
        mb_internal_encoding("UTF-8");
        $this->exclude = trim($this->exclude);
        if (strpos($this->exclude, ','))
        {
            $this->exclude = explode(',', $this->exclude);
            array_map('trim', $this->exclude);
        }
        elseif (empty($this->exclude) === false)
        {
            $this->exclude = array($this->exclude);
        }
        else
        {
            $this->exclude = array();
        }
        //convert alias to string
        if (count($this->exclude))
        {
            foreach ($this->exclude as $index => $exclude)
            {
                $excludeId = (int) $exclude;
                if ($excludeId == 0)
                    $excludeId = $this->getPageId($exclude, $siteId);
                $this->exclude[$index] = $excludeId;
            }
        }
        
        //get path
        if (self::$_path == null)
            self::$_path = Page::model()->getPath($pageId);
        Yii::trace('self::$_path: '.CVarDumper::dumpAsString(self::$_path), 'Page2Menu');
        Yii::trace('$this->rootId: '.CVarDumper::dumpAsString($this->rootId), 'Page2Menu');
        if ($this->level && $this->rootId == null)
        {
            if (is_array(self::$_path) && isset(self::$_path[$this->level]))
            {
                $this->rootId = (int) self::$_path[$this->level];
            }
            else
                $this->rootId = -1;
        }
        elseif ($this->rootId && ((int) $this->rootId) == 0)
        {
            $this->rootId = $this->getPageId($this->rootId, $siteId);
        }
        Yii::trace('$this->rootId: '.CVarDumper::dumpAsString($this->rootId), 'Page2Menu');
        
        //find pages change title and external pages
        $pagesChange = array();
        $pagesExternal = array();
        $pages = array();
        if (strlen($this->pages))
        {
            $this->pages = explode("\n", $this->pages);
            if (is_array($this->pages) && count($this->pages))
            {
                $this->pages = array_map('trim', $this->pages, array_fill(1, count($this->pages), "\n"));
                $this->pages = array_map('trim', $this->pages);
                Yii::trace('$this->pages: '.CVarDumper::dumpAsString($this->pages), 'Page2Menu');
                //parse item
                foreach ($this->pages as $item)
                {
                    if (empty($item)) continue;
                    preg_replace('/\s+/', ' ', $item);
                    $itemArr = explode(' ', $item);
                    $count = 0;
                    if (is_array($itemArr))
                        $count = count($itemArr);
                    if ($count >=3)
                    {
                        $pageId = $this->getPageId($itemArr[0], $siteId);
                        $href = $itemArr[1];
                        $title = mb_substr($item, strlen($itemArr[0])+strlen($href)+2);
                        Yii::trace('$title: '.CVarDumper::dumpAsString($title), 'Page2Menu');
                        if ($href === '#')//change title
                        {
                            $pages[] = $pageId;
                            $pagesChange[$pageId] = array(
                                'page_id'=>$pageId,
                                'title'=>$title,
                            );
                        }
                        else//external pages
                        {
                            $pagesExternal[] = array(
                                'before'=>$pageId,
                                'href'=>$href,
                                'title'=>$title,
                                'index'=>null,
                            );
                        }
                    }
                    elseif ($count == 1)
                    {
                        Yii::trace('$itemArr[0]: '.$itemArr[0], 'Page2Menu');
                        $pages[] = $this->getPageId($itemArr[0], $siteId);
                    }
                }
            }
        }
        
        Yii::trace('count $pages: '.CVarDumper::dumpAsString($pages), 'Page2Menu');
        $isCustomMenu = is_array($pages) && count($pages);
        
        $criteria=new CDbCriteria;
        $criteria->join = 'INNER JOIN '.SITE_TABLE_PREFIX.'page_current_revision pcr ON pcr.page_id = t.id';
        $criteria->compare('pcr.workflow_id', $workflowId);
        $criteria->compare('site_id', $siteId);
        $criteria->addNotInCondition('id', $this->exclude);
        $criteria->compare('status', true);
        if ($isCustomMenu)
        {
            $subCriteria = new CDbCriteria();
            $subCriteria->compare('parent_id', $this->rootId);
            $subCriteria->addInCondition('id', $pages, 'OR');
            $criteria->mergeWith($subCriteria);
        }
        else
            $criteria->compare('parent_id', $this->rootId);
        $criteria->order = 'ordering';
        $models = Page::model()->findAll($criteria);
        Yii::trace('count $models: '.count($models), 'Page2Menu');
        if (count($models))
        {
            foreach ($models as $index => $model)
            {
                $label = $model->title;
                //update title
                if (count($pagesChange))
                {
                    if (isset($pagesChange[$model->id]))
                        $label = $pagesChange[$model->id]['title'];
                }
                $item = array(
                    'label'=>$label,
                    'url'=>(is_object($model->defaultUrl) ? Yii::app()->request->hostInfo.Yii::app()->request->baseUrl.'/'.ltrim($model->defaultUrl->url, '/') : '#'),
                );                
                if (is_array(self::$_path) && in_array($model->id, self::$_path))
                    $item['active'] = true;
                if ($isCustomMenu)
                {
                    $index = array_search($model->id, $pages);
                }                    
                //update index for external pages
                if (count($pagesExternal))
                {
                    foreach ($pagesExternal as $i => $external)
                    {
                        if (!isset($external['index']) && abs($external['before']) == $model->id)
                        {
                            if ($external['before'] < 0)
                                $index++;
                            $pagesExternal[$i]['index'] = $index;
                        }
                    }
                }
                $this->_data[$index] = $item;
            }
            
            if ($isCustomMenu)
                ksort($this->_data);
            
            //add external pages
            if (count($pagesExternal))
            {
                Yii::trace('$pagesExternal: '.CVarDumper::dumpAsString($pagesExternal), 'Page2Menu');
                $data = new CList($this->_data);
                foreach ($pagesExternal as $item)
                {
                    $linkOptions = array('title'=>$item['title']);
                    if ((strpos($item['href'],'/') === 0) === false && strpos($item['href'],Yii::app()->request->getHostInfo()) === false)
                        $linkOptions['target'] = '_blank';
                    
                    $link = array(
                        'label'=>$item['title'],
                        'url'=>$item['href'],
                        'linkOptions' => $linkOptions,
                    );
                    if (isset($item['index']))
                    {
                        if ($data->offsetExists($item['index']))
                            $data->insertAt($item['index'], $link);
                        else
                            $data->add($link);
                    }
                    else if ($item['before'] == -1)
                    {
                        $data->add($link);
                    }
                        
                }
                $this->_data = $data->toArray();
            }
        }
        elseif (count($pagesExternal))
        {
            foreach ($pagesExternal as $item)
            {
                $linkOptions = array('title'=>$item['title']);
                if (strpos($item['href'],Yii::app()->request->getHostInfo()) === false)
                    $linkOptions['target'] = '_blank';
                
                $this->_data[] = array(
                    'label'=>$item['title'],
                    'url'=>$item['href'],
                    'linkOptions' => $linkOptions,
                );
            }
        }
        else
            $this->_data = array();
            
        if(isset($cache))
        {
            $sql = "SELECT last_update FROM ".SITE_TABLE_PREFIX."page ORDER BY last_update DESC LIMIT 1;";
            $dependency = new CDbCacheDependency($sql);
            $cache->set($key,serialize($this->_data), $this->expire, $dependency);
        }
    }
    
    protected function getPageId($data, $siteId)
    {
        $negative = false;
        $pageId = (int) $data;
        //find by alias
        if ($pageId === 0)
        {
            if (strpos($data, '-') === 0)
            {
                $data = substr($data, 1);
                $negative = true;
            }
            $page = null;
            $result = FSM::run('Cms.page.findByAlias', array('alias'=>$data, 'site_id'=>$siteId));
            if (!$result->hasErrors())
                $page = $result->model;
            if (is_object($page))
                $pageId = $page->id;
        }
        if ($negative)
            $pageId = -$pageId;
        return (int) $pageId;
    }
    
    public function run()
    {
        if (is_array($this->_data) && count($this->_data) >= $this->minItemsToShow)
        {
            mb_internal_encoding("UTF-8");
            return $this->widget('zii.widgets.CMenu', array(
                'items'=>$this->_data,
                'firstItemCssClass'=>'first',
            ), true);
        }
    }
}
